package cn.dansj.common.utils.spring.context.condition;

import cn.dansj.common.utils.lang.NotNull;
import cn.dansj.common.utils.reflect.ClassUtils;
import cn.dansj.common.utils.transfer.ArrayUtils;
import cn.dansj.common.utils.transfer.Transformation;
import cn.dansj.common.utils.transfer.Verification;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotatedTypeMetadata;

import java.util.Map;

@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition implements Condition {
    @Override
    public boolean matches(@NotNull ConditionContext context, @NotNull AnnotatedTypeMetadata metadata) {
        Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnClass.class.getName(), true);
        if (Verification.checkNull(attributes)) return false;
        return MatchType.Match.equals(attributes.get("matchType")) ? match(attributes, context, metadata) : miss(attributes, context);
    }

    private boolean match(Map<String, Object> attributes, ConditionContext context, AnnotatedTypeMetadata metadata) {
        return ArrayUtils.asList((String[]) attributes.get("name"), (String[]) attributes.get("value"), new String[]{ConditionalUtils.extractConfigClassName(metadata)}).stream().allMatch(cls -> ClassUtils.isPresent(cls, getClassLoader(context)));
    }

    private boolean miss(Map<String, Object> attributes, ConditionContext context) {
        return ArrayUtils.asList((String[]) attributes.get("name"), (String[]) attributes.get("value")).stream().noneMatch(cls -> ClassUtils.isPresent(cls, getClassLoader(context)));
    }

    private ClassLoader getClassLoader(ConditionContext context) {
        return Transformation.requireNonNullElseGet(context.getClassLoader(), ClassUtils::getDefaultClassLoader);
    }
}
